package it.uniroma3.dia.ia.textcategorization.persistence.filesystem;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;

import it.uniroma3.dia.ia.textcategorization.persistence.PersistenceException;
import it.uniroma3.dia.ia.textcategorization.persistence.TextPersistenceManager;
import it.uniroma3.dia.ia.textcategorization.texcat.TexCatConfiguration;

public final class FileSystemTextPersistenceManager implements
		TextPersistenceManager {

	private static final int MAX_ATTEMPT = 5;
	private static final String WORKING_DIRECTORY = TexCatConfiguration
			.getWorkspacePathname() + "/texts/";

	private static final FileSystemTextPersistenceManager instance = new FileSystemTextPersistenceManager();

	private FileSystemTextPersistenceManager() {
		ensureWorkingDirectoryExistence();
	}

	public static FileSystemTextPersistenceManager getInstance() {
		return instance;
	}

	@Override
	public String saveText(InputStream text) {
		try {
			String id = getId();
			write(text, id);
			return id;
		} catch (IOException exception) {
			throw new PersistenceException("Failed to save Text instance.",
					exception);
		}
	}

	@Override
	public InputStream loadText(String textId) {
		try {
			String filePathName = WORKING_DIRECTORY + textId + ".txt";
			return new FileInputStream(filePathName);
		} catch (FileNotFoundException exception) {
			throw new PersistenceException("Failed to load Text instance.",
					exception);
		}
	}
	
	@Override
	public void deleteText(String textId) {
		File file = new File(WORKING_DIRECTORY + textId + ".txt");
		file.delete();
	}

	private String getId() {
		String id = null;
		int attempts = 0;
		boolean found = false;
		while (attempts <= MAX_ATTEMPT && !found) {
			id = getRandomId();
			File file = new File(WORKING_DIRECTORY + id + ".txt");
			if (file.exists()) {
				attempts++;
			} else {
				found = true;
			}
		}
		if (found) {
			return id;
		} else {
			throw new PersistenceException("Failed to save Text instance. Max attempts to find a file name reached.");
		}
	}

	private String getRandomId() {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < 10; i++) {
			char c = getRandomLowerCaseAlfabeticChar();
			sb.append(c);
		}
		return sb.toString();
	}

	private char getRandomLowerCaseAlfabeticChar() {
		int asciiCode = 97 + (int) (Math.random() * 26);
		return (char) asciiCode;
	}

	private void write(InputStream text, String id) throws IOException {
		OutputStream output = new FileOutputStream(WORKING_DIRECTORY + id
				+ ".txt");
		BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
				output));
		BufferedReader reader = new BufferedReader(new InputStreamReader(text));
		String line = reader.readLine();
		while (line != null) {
			writer.write(line + "\n");
			line = reader.readLine();
		}
		writer.close();
		reader.close();
	}
	
	private void ensureWorkingDirectoryExistence() {
		File working_directory = new File(WORKING_DIRECTORY);
		if (!working_directory.exists()) {
			working_directory.mkdir();
		}
	}

}
